package com.da.prompts;

import java.util.*;
import java.util.regex.*;

/**
 * 智能模板处理类，支持三种模板类型：
 * 1. 命名模板（如 {name}）：通过Map或键值对参数替换
 * 2. 索引模板（如 %s, %1$d）：通过位置参数替换
 * 3. 混合模板（同时包含两种占位符）：需要明确指定参数类型
 *
 * @author da
 * @time 2025/2/24 下午 4:57
 */
public class PromptTemplate {
    // 模板类型枚举
    private enum TemplateType {NAMED, INDEXED, MIXED}

    // 预编译正则表达式（提升性能）
    private static final Pattern NAMED_PATTERN = Pattern.compile("\\{(\\w+)}");  // 匹配 {key} 形式
    private static final Pattern INDEXED_PATTERN = Pattern.compile("%(?:(\\d+\\$)?[sdf])"); // 匹配 %s, %1$d 等形式
    private static final String DEFAULT_FORMAT = "%s";  // 默认格式替换符

    // 实例字段（final保证线程安全）
    private final String originalTemplate;   // 原始模板字符串
    private final TemplateType templateType; // 模板类型
    private final List<String> orderedKeys;  // 有序参数列表（仅命名模板需要）
    private final String compiledTemplate;   // 编译后的模板（优化处理后的字符串）

    /**
     * 构造函数
     *
     * @param template 模板字符串，不能为空
     * @throws IllegalArgumentException 如果模板为空或包含非法格式
     */
    public PromptTemplate(String template) {
        this.originalTemplate = validateTemplate(template);
        this.templateType = detectTemplateType(template);
        this.orderedKeys = extractOrderedKeys(template);
        this.compiledTemplate = compileTemplate(template);
    }

    /**
     * 自动适配参数类型的格式化方法
     *
     * @param args 参数数组（命名模板需要键值对参数）
     * @return 格式化后的字符串
     * @throws IllegalArgumentException 参数类型不匹配时抛出
     */
    public String format(Object... args) {
        switch (templateType) {
            case NAMED:
                return formatNamed(convertToMap(args));  // 将键值对转为Map处理
            case INDEXED:
                return String.format(compiledTemplate, args); // 直接使用位置参数
            case MIXED:
                throw new IllegalArgumentException("混合模板需明确指定参数类型（使用Map参数）");
            default:
                throw new IllegalArgumentException("未知的模板类型：" + templateType);
        }
    }

    /**
     * 使用Map参数的格式化方法
     *
     * @param params 参数Map
     * @return 格式化后的字符串
     * @throws IllegalArgumentException 参数类型不匹配时抛出
     */
    public String format(Map<String, Object> params) {
        switch (templateType) {
            case NAMED:
                return formatNamed(params);
            case INDEXED:
                return formatIndexedWithMap(params); // 将Map转为有序参数列表
            case MIXED:
                return processMixedTemplate(params);    // 混合模板特殊处理
            default:
                throw new IllegalArgumentException("未知的模板类型：" + templateType);
        }
    }

    /******************** 核心实现 ********************/

    // 处理命名模板（使用有序参数列表）
    private String formatNamed(Map<String, Object> params) {
        Object[] orderedArgs = orderedKeys.stream()
                .map(k -> params.getOrDefault(k, ""))
                .toArray();
        return String.format(compiledTemplate, orderedArgs);
    }

    // 处理索引模板（使用Map参数）
    private String formatIndexedWithMap(Map<String, Object> params) {
        Object[] args = orderedKeys.stream()
                .map(k -> params.getOrDefault(k, ""))
                .toArray();
        return String.format(compiledTemplate, args);
    }

    // 处理混合模板（需要同时处理两种占位符）
    private String processMixedTemplate(Map<String, Object> params) {
        // 先处理命名参数
        Matcher namedMatcher = NAMED_PATTERN.matcher(originalTemplate);
        StringBuffer sb = new StringBuffer();
        while (namedMatcher.find()) {
            String key = namedMatcher.group(1);
            Object value = params.getOrDefault(key, "");
            namedMatcher.appendReplacement(sb, Matcher.quoteReplacement(value.toString()));
        }
        namedMatcher.appendTail(sb);

        // 再处理索引参数
        return String.format(sb.toString(), params.values().toArray());
    }

    /******************** 模板预处理 ********************/

    // 检测模板类型
    private TemplateType detectTemplateType(String template) {
        boolean hasNamed = NAMED_PATTERN.matcher(template).find();
        boolean hasIndexed = INDEXED_PATTERN.matcher(template).find();

        if (hasNamed && hasIndexed) return TemplateType.MIXED;
        if (hasNamed) return TemplateType.NAMED;
        return TemplateType.INDEXED;
    }

    // 提取有序参数列表（命名模板专用）
    private List<String> extractOrderedKeys(String template) {
        if (templateType == TemplateType.NAMED) {
            List<String> keys = new ArrayList<>();
            Matcher m = NAMED_PATTERN.matcher(template);
            while (m.find()) {
                String key = m.group(1);
                if (!keys.contains(key)) {  // 去重处理
                    keys.add(key);
                }
            }
            return Collections.unmodifiableList(keys);
        }
        return Collections.emptyList();
    }

    // 编译模板（将命名模板转换为标准格式字符串）
    private String compileTemplate(String template) {
        switch (templateType) {
            case NAMED:
                return NAMED_PATTERN.matcher(template).replaceAll(DEFAULT_FORMAT);
            case INDEXED:
                return template.replaceAll("%(?=\\d*\\$)", "%"); // 转义Java格式化符号
            case MIXED:
                return template;  // 混合模板保持原样
            default:
                throw new IllegalArgumentException("未知的模板类型：" + templateType);
        }
    }

    /******************** 参数处理 ********************/

    // 将键值对参数转换为Map
    private Map<String, Object> convertToMap(Object[] args) {
        if (args.length % 2 != 0) {
            throw new IllegalArgumentException("参数数量必须为偶数（键值对形式），实际收到：" + args.length + "个参数");
        }

        Map<String, Object> map = new LinkedHashMap<>();
        for (int i = 0; i < args.length; i += 2) {
            String key = args[i].toString();
            Object value = args[i + 1];
            if (map.containsKey(key)) {
                throw new IllegalArgumentException("重复的参数键：" + key);
            }
            map.put(key, value);
        }
        return map;
    }

    // 模板基础校验
    private static String validateTemplate(String template) {
        if (template == null || template.trim().isEmpty()) {
            throw new IllegalArgumentException("模板不能为空或空白");
        }
        return template;
    }

    @Override
    public String toString() {
        return "PromptTemplate[" + originalTemplate + "]";
    }
}
